from owlready2 import *

onto = get_ontology("http://test.org/onto.owl")

with onto:
    class Drug(Thing):
        def take(self): print("I took a drug")

    class ActivePrinciple(Thing):
        pass

    class has_for_active_principle(Drug >> ActivePrinciple):
        python_name = "active_principles"

    class Placebo(Drug):
        equivalent_to = [Drug & Not(has_for_active_principle.some(ActivePrinciple))]
        def take(self): print("I took a placebo")

    class SingleActivePrincipleDrug(Drug):
        equivalent_to = [Drug & has_for_active_principle.exactly(1, ActivePrinciple)]
        def take(self): print("I took a drug with a single active principle")

    class DrugAssociation(Drug):
        equivalent_to = [Drug & has_for_active_principle.min(2, ActivePrinciple)]
        def take(self): print("I took a drug with %s active principles" % len(self.active_principles))

acetaminophen   = ActivePrinciple("acetaminophen")
amoxicillin     = ActivePrinciple("amoxicillin")
clavulanic_acid = ActivePrinciple("clavulanic_acid")

AllDifferent([acetaminophen, amoxicillin, clavulanic_acid])

drug1 = Drug(active_principles = [acetaminophen])
drug2 = Drug(active_principles = [amoxicillin, clavulanic_acid])
drug3 = Drug(active_principles = [])

close_world(Drug)

# 推理前, 创建所有类、属性、个体, 还需要确认约束、不相交、区别已经合理
# sync_readoner()会将推理事实放入'http://inferrences/', 通过with onto可以访问它们
with onto:
    onto.save('owl/before_infer.owl')
    # sync_reasoner()
    # 如果需要推理对象的属性值可以指定参数
    # sync_reasoner(infer_property_values=True)
    # 使用Pellet而非HermiT
    # sync_reasoner_pellet()
    # Pellet支持推理DataPropert的值如下:
    sync_reasoner_pellet(infer_property_values = True, infer_data_property_values = True)
    # 通常会将推理后的结果存储下来
    onto.save('owl/after_infer.owl')
    # 返回自动分类结果
    print("drug2 new Classes:", drug2.__class__)
    drug1.take()
    drug2.take()
    drug3.take()
    # 返回不一致的类和本体
    list(default_world.inconsistent_classes())
    # 可以通过检查Nothing
    if Nothing in Drug.equivalent_to:
        print("Drug is inconsistent!")
        
# 查询推理分类: get_parents_of(entity), get_instancs_of(Class), get_children_of(entity)
inferences = get_ontology("http://test.org/onto_inferences1.owl")
with inferences:
    sync_reasoner()
    print('\tinferences.get_parents_of(drug1): ', inferences.get_parents_of(drug1))
    # [onto.SingleActivePrincipleDrug]
    print('\tdrug1.is_a: ', drug1.is_a)
    # [onto.has_for_active_principle.only(OneOf([onto.acetaminophen])), onto.SingleActivePrincipleDrug]